package main

import (
	"fmt"
	"knowledge-go/cpt/c_000_com"
	"os"
	"strconv"
	"strings"
)

/*
函数声明包括函数名、形式参数列表、返回值列表（可省略）以及函数体。

	func name(parameter-list) (result-list) {
	    body
	}
*/
func main() {
	fmt.Println(t1(1, "张三"))

	fmt.Println(digui(1))
	fmt.Println(digui(2))
	fmt.Println(digui(3))
	fmt.Println(digui(4))
	fmt.Println(digui(5))

	// 返回匿名函数
	var a func() int = squares()
	fmt.Println("调用匿名函数1", a())

	// 定义匿名函数
	upstr := func(str string) string {
		return strings.ToUpper(str)
	}

	ups := upstr("abc")
	fmt.Println("调用匿名函数2", ups)

	//strings.Map对字符串中的每个字符调用add1函数，并将每个add1函数的返回值组成一个新的字符串返回给调用者
	s3 := strings.Map(func(r rune) rune {
		return r + 1
	}, "aaa")
	fmt.Println(s3)

	// 可变参数长度
	fmt.Println("可变参数长度", sum(1, 2, 3))
	fmt.Println("可变参数长度", sum(1, 2, 3, 4))

	//interface{}表示函数的最后一个参数可以接收任意类型
	linenum, name := 12, "count"
	errorf(linenum, "undefined: %s", name) // "Line 12: undefined: count"

	/*
		参数拷贝。当调用一个函数时，会对其每一个参数值进行拷贝。如果需要修改参数数据，或者不想产生较大的对象拷贝，就考虑使用指针
		内存地址1： 0xc0000a6b78 824634327448 824634327472
		内存地址2： 0xc0000a6ba0 824634327496 824634327520
	*/
	num := 1
	nums := []int{1, 2, 3}
	user := c_000_com.User{Id: 1, Name: "张三"}
	fmt.Println("内存地址1：", &num, c_000_com.GetStructAddress(&nums), c_000_com.GetStructAddress(&user))
	tcc(num, nums, user)
}

func tcc(num int, nums []int, user c_000_com.User) {
	fmt.Println("内存地址2：", &num, c_000_com.GetStructAddress(&nums), c_000_com.GetStructAddress(&user))
}

// 多个返回值
func t1(id int, name string) (string, string, string) {
	return strconv.Itoa(id), name, "666"
}

// 多个返回值，并且设置返回值的变量
func t1_1(id int, name string) (n1 string, n2 string) {
	// 这里是修改值，而不是赋值
	n1 = "11"
	n2 = "22"
	return n1, n2
}

// 单个返回值
func t2(id int, name string) string {
	return strconv.Itoa(id)
}

// 多个同类型参数
func t3(id, age, num int, name string) {
}

// 模拟递归，n的阶乘
func digui(num int) int {
	if num == 1 {
		return 1
	}
	return digui(num-1) * num
}

// 函数返回函数
func squares() func() int {
	x := 2
	return func() int {
		x++
		return x * x
	}
}

func sum(nums ...int) int {
	total := 0
	for _, num := range nums {
		total += num
	}
	return total
}

// interface{}表示函数的最后一个参数可以接收任意类型
func errorf(linenum int, format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "Line %d: ", linenum)
	fmt.Fprintf(os.Stderr, format, args...)
	fmt.Fprintln(os.Stderr)
}
